package com.webSocket;

import java.io.IOException;
import java.util.Map;
import java.util.Map.Entry;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.CopyOnWriteArraySet;
import javax.websocket.*;
import javax.websocket.server.PathParam;
import javax.websocket.server.ServerEndpoint;

import net.sf.json.JSONArray;
import net.sf.json.JSONObject;

/**
 * @ServerEndpoint 注解是一个类层次的注解，它的功能主要是将目前的类定义成一个websocket服务器端,
 *                 注解的值将被用于监听用户连接的终端访问URL地址,客户端可以通过这个URL来连接到WebSocket服务器端
 */
@ServerEndpoint(value = "/WebRtc/{param}")
public class WebRtc {
    // 静态变量，用来记录当前在线连接数。应该把它设计成线程安全的。
    private static int onlineCount;
    // concurrent包的线程安全Set，用来存放每个客户端对应的MyWebSocket对象。若要实现服务端与单一客户端通信的话，可以使用Map来存放，其中Key可以为用户标识
    //private static CopyOnWriteArraySet<WebSocketOneToOne> webSocketSet = new CopyOnWriteArraySet<WebSocketOneToOne>();
    private static Map<String,WebRtc> connections = new ConcurrentHashMap<>();
    // 与某个客户端的连接会话，需要通过它来给客户端发送数据
    private Session session;
    private String role;
    private String socketId;

    /**
     * 连接建立成功调用的方法
     * 
     * @param session
     *            可选的参数。session为与某个客户端的连接会话，需要通过它来给客户端发送数据
     */
    @OnOpen
    public void onOpen(@PathParam("param") String param,Session session) {
        this.session = session;
        String[] arr = param.split(",");
        this.role = arr[0];
        this.socketId = arr[1];
        //webSocketSet.add(this); // 加入set中
        connections.put(role,this);  
        broadcast("{\"event\":\"msg\",\"data\":\""+role+"\"}",socketId);
        addOnlineCount(); // 在线数加
        System.out.println("有新连接加入！新用户："+role+",当前在线人数为" + getOnlineCount());
        //获取已经在房间中的人数
        JSONArray array=new JSONArray();
        for (Entry<String, WebRtc> client  : connections.entrySet()) {
            if(client.getValue().socketId.equals(socketId)||client.getValue().socketId==socketId){
                array.add(client.getKey());
            }
        }
        send("{\"event\":\"rolelist\",\"data\":"+array.toString()+"}", role,socketId);
    }

    /**
     * 连接关闭调用的方法
     */
    @OnClose
    public void onClose() {
        connections.remove(role);  
        //webSocketSet.remove(this); // 从set中删除
        subOnlineCount(); // 在线数减
        System.out.println("有一连接关闭！当前在线人数为" + getOnlineCount());
        String msg=("{\"event\":\"role\",\"data\":\""+role+"\"}");
        broadcast(msg,socketId);
    }

    /**
     * 收到客户端消息后调用的方法
     * 
     * @param message
     *            客户端发送过来的消息
     * @param session
     *            可选的参数
     */
    @OnMessage
    public void onMessage(String message, Session session) {
        System.out.println("来自客户端的消息:" + message);
        JSONObject json=JSONObject.fromObject(message);
        String string = null;
        String to = null;
        if(json.has("message")){
             string = (String) json.get("message");
        }
        if(json.has("role")){
             to = (String) json.get("role");
        }
        send(string,role,to,socketId);
        // 群发消息
        /*for (WebSocketTest item : webSocketSet) {
            try {
                item.sendMessage(string);
            } catch (IOException e) {
                e.printStackTrace();
                continue;
            }
        }*/
    }

    /**
     * 发生错误时调用
     * 
     * @param session
     * @param error
     */
    @OnError
    public void onError(Session session, Throwable error) {
        System.out.println("发生错误");
        error.printStackTrace();
    }

    /**
     * 这个方法与上面几个方法不一样。没有用注解，是根据自己需要添加的方法。
     * 
     * @param message
     * @throws IOException
     */
    public void sendMessage(String message) throws IOException {
        this.session.getBasicRemote().sendText(message);
        // this.session.getAsyncRemote().sendText(message);
    }
    
    //发送给指定角色
    public static void send(String msg,String from,String to,String socketId){
        try {
            //to指定用户
            WebRtc con = connections.get(to);
            if(con!=null){
                if(socketId==con.socketId||con.socketId.equals(socketId)){
                    con.session.getBasicRemote().sendText(from+"说："+msg);   
                }
    
            }
            //from具体用户
            WebRtc confrom = connections.get(from);
            if(confrom!=null){
                if(socketId==confrom.socketId||confrom.socketId.equals(socketId)){
                    confrom.session.getBasicRemote().sendText(from+"说："+msg);   
                }
    
            }
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }
    
    public static void broadcast(String msg,String socketId) {  
        for (Entry<String, WebRtc> client : connections.entrySet()) {  
            try {  
                synchronized (client) {  
                    if(client.getValue().socketId==socketId||client.getValue().socketId.equals(socketId)){
                        client.getValue().session.getBasicRemote().sendText(msg);   
                    }
         
                }  
            } catch (IOException e) {  
                System.out.println("Chat Error: Failed to send message to client");  
                connections.remove(client);  
                try {  
                    client.getValue().session.close();  
                } catch (IOException e1) {  
                    // Ignore  
                }  
                String message = String.format("* %s %s",  
                        client.getValue().role, " has been disconnected.");  
                broadcast(message,socketId);  
            }  
        }  
    }  
     public static void send(String msg,String to,String socketId){
            try {
                WebRtc con = connections.get(to);
                if(con!=null){
                    if(socketId==con.socketId||con.socketId.equals(socketId)){
                        con.session.getBasicRemote().sendText(msg); 
                    }
        
                }
            } catch (IOException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
        }

    public static synchronized int getOnlineCount() {
        return onlineCount;
    }

    public static synchronized void addOnlineCount() {
        WebRtc.onlineCount++;
    }

    public static synchronized void subOnlineCount() {
        WebRtc.onlineCount--;
    }
}